package plugin.demo.shardingsphere.xa.controller;

import com.alibaba.fastjson.JSON;
import icasue.net.protocol.http.HttpOption;
import icasue.net.protocol.http.HttpProtocol;
import icasue.net.protocol.http.HttpResponse;
import icasue.net.protocol.http.utils.SocketUtil;
import org.apache.shardingsphere.infra.hint.HintManager;
import org.apache.shardingsphere.transaction.annotation.ShardingTransactionType;
import org.apache.shardingsphere.transaction.core.TransactionType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import plugin.demo.shardingsphere.xa.service.TestClsService;
import plugin.demo.shardingsphere.xa.utils.DBUtils;

import javax.sql.DataSource;
import java.io.IOException;
import java.nio.charset.Charset;
import java.sql.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author: Qiao Hang
 * @CreateDate: 2021/4/20 下午5:09
 * @UpdateDate:
 * @Description:
 */
@RestController
public class TestClsController {

    @Autowired
    TestClsService testClsService;

    @GetMapping("getAll")
    public Object getAll(){
        return testClsService.getAll();
    }
    @PostMapping("insert")
    public Object insert(@RequestBody Map<String,String> row){
        return testClsService.insert(row);
    }
    @PostMapping("update")
    public Object update(@RequestBody Map<String,String> row){
        return testClsService.update(row);
    }

    @Autowired
    DataSource dataSource;

    @PostMapping("query")
    public Object query(@RequestBody Map<String,String> body){
        String sql = body.get("sql");
        if(sql == null) return null;

        Object res = null;
        try (
                Connection connection = dataSource.getConnection();
                PreparedStatement preparedStatement = connection.prepareStatement(sql)
        ){
            ResultSet resultSet = preparedStatement.executeQuery();
            res =  DBUtils.convertList(resultSet);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return res;
    }


    @PostMapping("persist")
    public Object persist(@RequestBody Map<String,String> body){
        String sql = body.get("sql");
        if(sql == null) return null;

        Object res = null;
        try (
                Connection connection = dataSource.getConnection();
                PreparedStatement preparedStatement = connection.prepareStatement(sql)
        ){
            boolean execute = preparedStatement.execute();
            res =  execute;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return res;
    }


    @PostMapping("persistPlus")
    public Object persistPlus(@RequestBody Map<String,Object> body){
        String sql = (String)body.get("sql");
        if(sql == null) return null;

        List<String> params = (List<String>) body.get("params");

        Object res = null;
        try (
                Connection connection = dataSource.getConnection();
                PreparedStatement preparedStatement = connection.prepareStatement(sql)
        ){
            for (int i = 1; i <= params.size(); i++) {
                String[] split = params.get(i-1).split(";");
                String type = split[0];
                if(type.equals("int")){
                    preparedStatement.setInt(i,Integer.parseInt(split[1]));
                }else if(type.equals("long")){
                    preparedStatement.setLong(i,Long.parseLong(split[1]));
                }else if(type.equals("float")){
                    preparedStatement.setFloat(i,Float.parseFloat(split[1]));
                }else if(type.equals("double")){
                    preparedStatement.setDouble(i,Double.parseDouble(split[1]));
                } else if(type.equals("string")){
                    preparedStatement.setString(i,split[1]);
                }
            }
            boolean execute = preparedStatement.execute();
            res =  execute;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return res;
    }


    @PostMapping("queryHit")
    public Object queryHint(@RequestBody Map<String,Object> body){
        String sql = (String)body.get("sql");
        if(sql == null) return null;

        Object tab = body.get("tab");
        Object tabVal = body.get("tabVal");
        Object dbVal = body.get("dbVal");
        Object dbChoose = body.get("dbChoose");
        Object primary = body.get("primaryKey");

        Object res = null;
        try (
                Connection connection = dataSource.getConnection();
                PreparedStatement preparedStatement = connection.prepareStatement(sql)
        ){
            HintManager instance = null;
            if((tab != null && tabVal != null) || dbVal != null || dbChoose != null || primary != null){
                instance = HintManager.getInstance();
            }
            if(tab != null && tabVal != null){
                System.out.println("tab:" + tab + " ,tabVal:"+tabVal);
                instance.addTableShardingValue(tab.toString(),Comparable.class.cast(tabVal));
            }
            if(dbVal != null){
                System.out.println("dbVal:"+dbVal);
                instance.addDatabaseShardingValue(tab.toString(),Comparable.class.cast(dbVal));
            }
            if(dbChoose != null){
                System.out.println("dbChoose:" + dbChoose);
                instance.setDatabaseShardingValue(Comparable.class.cast(dbChoose));
            }
            if(primary != null){
                instance.setPrimaryRouteOnly();
            }
            boolean execute = preparedStatement.execute();
            res =  execute;
            if(instance != null){
                instance.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return res;
    }

    @GetMapping("transaction")
    @Transactional
    @ShardingTransactionType(TransactionType.XA) //开启XA强一致性事务.
    public Object transaction(@RequestParam Boolean doError,@RequestParam Boolean selfError) throws IOException {

        //id,cls_desc generic  数据根据uid落库3片, order_id落库两片，到master(dn0): dn0:test -> test_order_1 上.
        String test_order_sql = "insert into test_order(`uid`,`order_id`) values(30,31)";
        HashMap<String, Object> order = new HashMap<String, Object>() {{
            put("uid", 30);
            put("order_id", 31);
        }};
        testClsService.insertOrder(order);


        //id generic, 数据根据uid落库3片, order_id落库两片，到master(dn0): dn1:test2 -> order_item_1 上.
        String order_item_sql = "insert into order_item(`uid`,`order_id`,`order_item_id`) values(31,31,1),(31,31,2),(31,31,3),";
        HashMap<String, Object> orderItems = new HashMap<String, Object>() {{
            put("uid", 31);
            put("order_id", 31);
            put("itemIds", Arrays.asList(1,2,3));
        }};
        testClsService.insertOrderItem(orderItems);

        /*调用外部系统，进行pay_info, delivery_info的落库*/
        StringBuffer protocol = HttpProtocol.builder(HttpOption.V1_1.GET, "/transaction")
                .query("doError",doError == null ? Boolean.FALSE : doError)
                .build("127.0.0.1");
        HttpResponse<String> result = SocketUtil.send("127.0.0.1", 8081,
                Charset.forName("UTF-8"), protocol, String.class, null, null);
        System.out.println(JSON.toJSONString(result));

        if(selfError != null && selfError.equals(Boolean.TRUE)){
            int error = 1 / 0;
        }
        return Boolean.TRUE;
    }


    public static void main(String[] args) {
//        String url = "jdbc:mysql://tsp-sit-mysql.beantechyun.cn:3306/lbs_basic_microservice?userSSL=true&useUnicode=true&characterEncoding=UTF8&serverTimezone=Asia/Shanghai";
        String url = "jdbc:mysql://tsp-sit-mysql.beantechyun.cn:3306/lbs_basic_microservice";
        int i = url.indexOf("?");
        if(i < 0){
            System.out.println(url.substring(url.lastIndexOf("/") + 1));
        }else {
            String subUrl = url.substring(0, i);
            System.out.println(subUrl.substring(subUrl.lastIndexOf("/") + 1));
        }

    }



}
